from string import *
import re
from yappsrt import *

class BuilderConfigurationScanner(Scanner):
    patterns = [
        ('";"', re.compile(';')),
        ('":"', re.compile(':')),
        ('"="', re.compile('=')),
        ('"}"', re.compile('}')),
        ('"{"', re.compile('{')),
        ('[ \t\r\n]+', re.compile('[ \t\r\n]+')),
        ('#.*?\r?\n', re.compile('#.*?\r?\n')),
        ('END', re.compile('$')),
        ('STR', re.compile('[rR]?\'([^\\n\'\\\\]|\\\\.)*\'|[rR]?"([^\\n"\\\\]|\\\\.)*"')),
        ('ID', re.compile('[a-zA-Z_][a-zA-Z_0-9\\-\\.\\+]*')),
        ('MACRO', re.compile('\\${[a-zA-Z_][a-zA-Z_0-9\\-\\.]*}')),
        ('MREF', re.compile('\\${[a-zA-Z_][a-zA-Z_0-9\\-\\.]*}')),
        ('LIST', re.compile(',')),
        ('SEP', re.compile(':')),
        ('FSLASH', re.compile('/')),
        ('BSLASH', re.compile('\\\\')),
        ('LEQ', re.compile('<=')),
        ('REQ', re.compile('=>')),
        ('PIPE', re.compile('\\|')),
        ('IOIN', re.compile('>')),
        ('NUM', re.compile('[0-9]+')),
        ('VER', re.compile('[0-9]([\\.\\-][0-9][\\.\\-0-9])+')),
        ('TEXT', re.compile('([/a-zA-z_0-9\\-\\.\\*\\?\\${}:])+')),
    ]
    def __init__(self, str):
        Scanner.__init__(self,None,['[ \t\r\n]+', '#.*?\r?\n'],str)

class BuilderConfiguration(Parser):
    def Config(self):
        groups = []
        while self._peek('END', 'ID', 'MACRO') != 'END':
            Group = self.Group()
            groups.append(Group)
        return('config', groups)
        END = self._scan('END')

    def Group(self):
        Label = self.Label()
        _token_ = self._peek('"{"', '"="')
        if _token_ == '"{"':
            self._scan('"{"')
            members = []
            while 1:
                Member = self.Member()
                members.append(Member)
                if self._peek('ID', 'MACRO', '"}"') not in ['ID', 'MACRO']: break
            self._scan('"}"')
            return('group', Label, members)
        else:# == '"="'
            self._scan('"="')
            Element = self.Element()
            return('macro', Label, Element)

    def Member(self):
        Label = self.Label()
        self._scan('":"')
        members = []
        while 1:
            Element = self.Element()
            members.append(Element)
            if self._peek('ID', 'LIST', 'SEP', 'FSLASH', 'BSLASH', 'LEQ', 'REQ', 'PIPE', 'IOIN', 'STR', 'NUM', 'VER', 'TEXT', '";"') not in ['ID', 'LIST', 'SEP', 'FSLASH', 'BSLASH', 'LEQ', 'REQ', 'PIPE', 'IOIN', 'STR', 'NUM', 'VER', 'TEXT']: break
        self._scan('";"')
        return ('member', Label, members)

    def Label(self):
        _token_ = self._peek('ID', 'MACRO')
        if _token_ == 'ID':
            ID = self._scan('ID')
            return('id', ID, self._scanner.pos)
        else:# == 'MACRO'
            MACRO = self._scan('MACRO')
            return('mref', MACRO, self._scanner.pos)

    def Macro(self):
        MACRO = self._scan('MACRO')
        self._scan('"="')
        Element = self.Element()
        return('macro', MACRO, Element)

    def Element(self):
        _token_ = self._peek('ID', 'LIST', 'SEP', 'FSLASH', 'BSLASH', 'LEQ', 'REQ', 'PIPE', 'IOIN', 'STR', 'NUM', 'VER', 'TEXT')
        if _token_ == 'ID':
            ID = self._scan('ID')
            return('id',      ID,        self._scanner.pos)
        elif _token_ == 'LIST':
            LIST = self._scan('LIST')
            return('list',    ',',       self._scanner.pos)
        elif _token_ == 'SEP':
            SEP = self._scan('SEP')
            return('sep',     ':',       self._scanner.pos)
        elif _token_ == 'FSLASH':
            FSLASH = self._scan('FSLASH')
            return('fslash',  '/',       self._scanner.pos)
        elif _token_ == 'BSLASH':
            BSLASH = self._scan('BSLASH')
            return('bslash',  '\\',      self._scanner.pos)
        elif _token_ == 'LEQ':
            LEQ = self._scan('LEQ')
            return('leq',     '<=',      self._scanner.pos)
        elif _token_ == 'REQ':
            REQ = self._scan('REQ')
            return('req',     '=>',      self._scanner.pos)
        elif _token_ == 'PIPE':
            PIPE = self._scan('PIPE')
            return('pipe',    '|',       self._scanner.pos)
        elif _token_ == 'IOIN':
            IOIN = self._scan('IOIN')
            return('redirin', '>',       self._scanner.pos)
        elif _token_ == 'STR':
            STR = self._scan('STR')
            return('str',     eval(STR), self._scanner.pos)
        elif _token_ == 'NUM':
            NUM = self._scan('NUM')
            return('num',     atoi(NUM), self._scanner.pos)
        elif _token_ == 'VER':
            VER = self._scan('VER')
            return('ver',     VER,       self._scanner.pos)
        else:# == 'TEXT'
            TEXT = self._scan('TEXT')
            return('text',    TEXT,      self._scanner.pos)


def parse(rule, text):
    P = BuilderConfiguration(BuilderConfigurationScanner(text))
    return wrap_error_reporter(P, rule)

if __name__ == '__main__':
    from sys import argv, stdin
    if len(argv) >= 2:
        if len(argv) >= 3:
            f = open(argv[2],'r')
        else:
            f = stdin
        print parse(argv[1], f.read())
    else: print 'Args:  <rule> [<filename>]'
